﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using BitBenderGames;
using com.yoozoo.gta.Extension.UGUI.ScreenOrientationEx;
using com.yoozoo.gta.Gameplay.RTS;
using com.youzu.warh.protocol;
using UnityEngine;
using UnityEngine.Networking;
using WorldMapBase;
using XLua;
using Yoozoo.Gameplay.RTS;
using Yoozoo.Gameplay.RTS.Proto;
using Yoozoo.Gta.Common;
using Yoozoo.Mars.Got;
using Yoozoo.Mars.Got.SpriteAnim;
using SCRoundFight = com.youzu.warh.protocol.SCRoundFight;

namespace Yoozoo.Gameplay.RTS
{
    public class RtsArenaManager
    {
        private static RtsArenaManager m_instance;
        
        private Dictionary<int,List<long>> marchList = new Dictionary<int,List<long>>();
        
        private List<TroopMarchKeyFrame> keyFrames = new List<TroopMarchKeyFrame>();
        private List<SCRoundFight> roundFights = new List<SCRoundFight>();

        private bool start = false;

        private bool isReadyToEnd;
        private long readyToEndTime;

        private long startTime;

        public Camera MainCamera;
        private MobileTouchCamera MobileTouchCamera;

        private ArenaBattleReport report;
        
        public Vector3 CenterPosition = Vector3.zero;

        public static bool IsTimeDebug = false;

        public int ArenaType = 0;//0 竞技场 1雷达 2rts推图

        private RtsArenaReportManager reportManager;

        public static string EventUid;

        public static RtsArenaManager Instance
        {
            get
            {
                if (m_instance == null)
                {
                    m_instance = new RtsArenaManager();
                    m_instance.Initialize();
                }
                return m_instance;
            }
        }

        public long playerId;
        
        public void SetPlayerId(long playerId)
        {
            this.playerId = playerId;
        }

        public void PreloadArenaInitConfig(LuaTable table,int type)
        {
            for (int i = 1; i <= table.Length; i++)
            {
                var config = table.Get<int, LuaTable>(i);
                if (config != null)
                {
                    int id = GetInt(config, "id");
                    float x = GetFloat(config, "x");
                    //float y = GetFloat(config, "y");
                    float z = GetFloat(config, "z");
                    MarchHelper.SetArenaInitPosition(id, x, z, type);
                }
            }
        }
        
        private int GetInt(LuaTable table, string key)
        {
            return table.ContainsKey(key) ? table.Get<string, int>(key) : 0;
        }

        private float GetFloat(LuaTable table, string key)
        {
            return table.ContainsKey(key) ? table.Get<string, float>(key) : 0;
        }

        public long GetServerTimeMs()
        {
            var deltaTick = (long)((Environment.TickCount - timeDebugStartClickTick) * timeScale);
            return deltaTick + timeDebugStartTime;
        }
        
        public long GetClientTimeMs()
        {
            var deltaTick = (long)((Environment.TickCount - timeDebugStartClickTick) * timeScale);
            return deltaTick;
        }

        private long timeDebugStartTime;
        private long timeDebugStartClickTick;
        private float timeScale = 1;
        
        public void SetTimeScale(float timeScale)
        {
            timeDebugStartTime = TimeUtils.GetServerTimeMs();
            timeDebugStartClickTick = Environment.TickCount;
            this.timeScale = timeScale;
            RtsArenaManager.IsTimeDebug = true;
        }
        
        
        public void Initialize()
        {
            reportManager = new RtsArenaReportManager();
            reportManager.Initialize();
        }

        private Action testAction;
        
        public void Update()
        {
            #if UNITY_EDITOR
            if (start)
            {
                if (Input.GetKeyDown(KeyCode.Q))
                {
                    SetTimeScale(timeScale / 2);
                }
                if (Input.GetKeyDown(KeyCode.E))
                {
                    SetTimeScale(timeScale * 2);
                }
            }
#endif
            if (testAction != null)
            {
                testAction.Invoke();
                testAction = null;
            }

            reportManager?.Update();

            if (isLogicPause)
            {
                return;
            }         
            
            if (start)
            {
                if (!isReadyToEnd)
                {
                    if (!isPause)
                    {
                        UpdateReplay();
                    }
                    if (roundFights?.Count == 0 && keyFrames?.Count == 0)
                    {
                        isReadyToEnd = true;
                        readyToEndTime = TimeUtils.GetServerTimeMs();
                    }
                }
                else
                {
                    if (TimeUtils.GetServerTimeMs() - readyToEndTime > 1500)
                    {
                        EndReplay();
                    }
                }
              
            }
        }

        public void AddTestAction(Action action)
        {
            testAction = action;
        }

        public void Start()
        {
            IsTimeDebug = false;
            timeScale = 1;
            PrepareBattle();
            StartReplay();
        }
        public void EndReplay(bool isQuit = false)
        {
            UnApplyCamera();
            StopReplay();
            if (ArenaType == 0)
            {
                ResidentHandler.Inst.GetFunction("L_RtsArenaManager.OnEndReplay").Action();
            }
            else if (ArenaType == 1)
            {
                ResidentHandler.Inst.GetFunction("L_RadarArenaManager.OnEndReplay").Action(isQuit,EventUid);
            }
            else
            {
                ResidentHandler.Inst.GetFunction("L_RtsExpeditionManager.OnEndReplay").Action();
            }
        }

        public void StopReplay()
        {
            start = false;
            isReadyToEnd = false;
            isLogicPause = false;
        }

        public void OnReportReady(ArenaBattleReport report)
        {
#if UNITY_EDITOR
            // FileStream fs = new FileStream("E:/Caches/testReplay.txt", FileMode.Create);
            // string jsonString = "";
            // jsonString += LogSummary(report.reportSummary);
            // jsonString += LogContent(report.reportContent);
            // fs.Write(Encoding.UTF8.GetBytes(jsonString), 0, jsonString.Length);
            // fs.Close();
#endif
            this.report = report;
            if (start)
            {
                Clear();
                Start();
            }
            else
            {
                if (ArenaType == 0)
                {
                    ResidentHandler.Inst.GetFunction("L_RtsArenaManager.OnReportReady").Action();
                }
                else if (ArenaType == 1)
                {
                    ResidentHandler.Inst.GetFunction("L_RadarArenaManager.OnReportReady").Action();
                }
                else
                {
                    ResidentHandler.Inst.GetFunction("L_RtsExpeditionManager.OnReportReady").Action();
                }
            }
        }
        
        public void PrepareBattle()
        {
            var reportSummary = report.reportSummary;
            //获取初始部队和站位
            var left = reportSummary.leftCamp;
            for (int i = 0; i < left.troops.Count; i++)
            {
                var troop = left.troops[i];
                CreateBattleUnit(troop,0,ArenaType);
            }
            
            var right = reportSummary.rightCamp;
            for (int i = 0; i < right.troops.Count; i++)
            {
                var troop = right.troops[i];
                CreateBattleUnit(troop,2, ArenaType);
            }

            //显示UI
            if (ArenaType == 0)
            {
                ResidentHandler.Inst.GetFunction("L_RtsArenaManager.ShowRtsArenaBattle").Action(left, right);
            }
            else if (ArenaType == 1)
            {
                ResidentHandler.Inst.GetFunction("L_RadarArenaManager.ShowRtsArenaBattle").Action(left, right, reportSummary.reportId);
            }
            else
            {
                ResidentHandler.Inst.GetFunction("L_RtsExpeditionManager.ShowRtsArenaBattle").Action(left, right, reportSummary.reportId);
            }
        }


        private long pauseStartTime;
        private bool isPause = false;
        public void OnApplicationPause(bool isPause)
        {
            this.isPause = isPause;
            if (!start)
            {
                return;
            }
            if (isPause)
            {
                pauseStartTime = TimeUtils.GetServerTimeMs();
            }
            else
            {
                if (pauseStartTime > 0)
                {
                    pauseTime = TimeUtils.GetServerTimeMs() - pauseStartTime;
                }
                else
                {
                    pauseTime = 0;
                }
            }
        }

        private bool isLogicPause = false;
        
        public void Pause()
        {
            isLogicPause = true;
            logicPauseStartTime = TimeUtils.GetServerTimeMs();
        }

        public void Resume()
        {
            isLogicPause = false;
            if (!isPause)
            {
                if (logicPauseStartTime > 0)
                {
                    pauseTime = TimeUtils.GetServerTimeMs() - logicPauseStartTime;
                }
                else
                {
                    pauseTime = 0;
                }
            }
        }
        
        public void StartReplay()
        {
            isLogicPause = false;
            if (start)
            {
                Debug.LogError("[RTS竞技场]StartReplay重复调用");
                return;
            }
            MarchManager.Instance.IsInArena = true;
            var reportContent = report.reportContent;
            if (reportContent == null)
            {
                return;
            }
            keyFrames.Clear();
            keyFrames.AddRange(reportContent.keyFrame);
            roundFights.Clear();
            roundFights.AddRange(reportContent.roundFight);

            start = true;
            startTime = TimeUtils.GetServerTimeMs();
            pauseTime = 0;
            isPause = false;
            ApplyCamera();
        }

        private int leftTime = -1;
        private int totalBattleTime = 180;
        private int rtsArenaTotalBattleTime = 180;
        //玩家点手机的返回按钮，触发的全局暂停
        private long pauseTime = 0;
        //玩家点左上角的返回按钮，触发的逻辑暂停
        private long logicPauseStartTime = 0;
        
        private void UpdateReplay()
        {
            var deltaTime = TimeUtils.GetServerTimeMs() - startTime - pauseTime;
            var keyFrameExecuteCount = 0;
            if (keyFrames != null)
            {
                for (int i = 0; i < keyFrames.Count; i++)
                {
                    if (keyFrames[i].lastFrameTime <= deltaTime)
                    {
                        MarchManager.Instance.UpdateArenaKeyFrame(keyFrames[i],startTime);
                        var marchStatusToInt = (int) keyFrames[i].marchStatus;
                        if (marchStatusToInt == 0)
                        {
                            marchStatusToInt = -1;
                        }
                        if (ArenaType == 0)
                        {
                            ResidentHandler.Inst.GetFunction("L_RtsArenaManager.UpdateTroopData").Action(keyFrames[i].troopId, marchStatusToInt);
                        }
                        else if (ArenaType == 1)
                        {
                            ResidentHandler.Inst.GetFunction("L_RadarArenaManager.UpdateTroopData").Action(keyFrames[i].troopId, marchStatusToInt);
                        }
                        else
                        {
                            ResidentHandler.Inst.GetFunction("L_RtsExpeditionManager.UpdateTroopData").Action(keyFrames[i].troopId, marchStatusToInt);
                        }
                        keyFrames.RemoveAt(i);
                        i--;
                        keyFrameExecuteCount++;
                    }
                    else
                    {
                        reportManager.needJumpToCurrentTime = false;
                    }
                }
            }

            //如果该帧运行了超过10个，则可能是时间出了问题，打印一下日志
            if (keyFrameExecuteCount > 10)
            {
                Debug.LogError("[RTS竞技场]单帧执行KeyFrame数量"+keyFrameExecuteCount);
                Debug.LogError(string.Format("[RTS竞技场]回放开始时间:{0},服务器时间:{1},当前时间:{2}",startTime,TimeUtils.GetServerTimeMs(),deltaTime));
            }

            var roundFightExecuteCount = 0;
            if (roundFights != null)
            {
                for (int i = 0; i < roundFights.Count; i++)
                {
                    if (roundFights[i].fightFrameTime <= deltaTime)
                    {
                        MarchManager.Instance.DoArenaRoundFight(roundFights[i]);
                        roundFights.RemoveAt(i);
                        i--;
                        roundFightExecuteCount++;
                    }
                }
            }
            //如果该帧运行了超过10个，则可能是时间出了问题，打印一下日志
            if (roundFightExecuteCount > 2)
            {
                Debug.LogError("[RTS竞技场]单帧执行RoundFight数量"+roundFightExecuteCount);
                Debug.LogError(string.Format("[RTS竞技场]回放开始时间:{0},服务器时间:{1},当前时间:{2}",startTime,TimeUtils.GetServerTimeMs(),deltaTime));
            }

            var leftTime = 0;
            if (ArenaType == 0)
            {
                leftTime = rtsArenaTotalBattleTime - (int)deltaTime / 1000;
            }
            else
            {
                leftTime = totalBattleTime - (int)deltaTime / 1000;
            }
            leftTime = Mathf.Max(leftTime, 0);
            if (leftTime != this.leftTime)
            {
                this.leftTime = leftTime;
                if (ArenaType == 0)
                {
                    ResidentHandler.Inst.GetFunction("L_RtsArenaManager.UpdateLeftTime").Action(leftTime);
                }
                else if (ArenaType == 1)
                {
                    ResidentHandler.Inst.GetFunction("L_RadarArenaManager.UpdateLeftTime").Action(leftTime);
                }
                else
                {
                    ResidentHandler.Inst.GetFunction("L_RtsExpeditionManager.UpdateLeftTime").Action(leftTime);
                }
            }
        }
        
        public void CreateBattleUnit(ArenaBattleTroop troop,int team,int arenaType)
        {
            ResidentHandler.Inst.GetFunction("L_RtsArenaManager.CreateArenaMarch").Action(new RtsArenaTroop{
                troop = troop,
                marchAnimation = 0
            },team,false, arenaType);
            if (!marchList.TryGetValue(team,out var teamList))
            {
                teamList = new List<long>();
                marchList.Add(team,teamList);
            }
            teamList.Add(troop.troopId);
        }

        public void SetRtsArenaTotalBattleTime(int battleTime)
        {
            rtsArenaTotalBattleTime = battleTime;
        }

        public void CreateFormationUnit(int _troopId,int _heroId, int _position, int _soldierId,int _soldiderCount, int _team,int type,string playerName = default, int _marchAnimation = 0)
        {
            int troopId = _troopId;
            int heroId = _heroId;
            int position = _position;
            int soldierId = _soldierId;
            int team = _team;
            int soldiderCount = _soldiderCount;
            int marchAnimation = _marchAnimation;
            Timers.inst.CallLater((o) =>
            {
                ArenaBattleTroop troop = new ArenaBattleTroop();
                troop.troopId = troopId;
                troop.heroList.Add(new ArenaHero() { heroId = heroId });
                troop.initPos = position;
                troop.soldier = new IntPair()
                {
                    key = soldierId,
                    value = soldiderCount,
                };
                var troopData = new RtsArenaTroop
                {
                    troop = troop,
                    playerName = playerName,
                    marchAnimation = marchAnimation,
                };
                try
                {
                    ResidentHandler.Inst.GetFunction("L_RtsArenaManager.CreateArenaMarch").Action(troopData, team,true,type);
                }
                catch (Exception e)
                {
                    Debug.LogError(e.ToString());
                }
      

                if (!marchList.TryGetValue(team, out var teamList))
                {
                    teamList = new List<long>();
                    marchList.Add(team, teamList);
                }
                teamList.Add(troop.troopId);
            });
        }

        public void Clear()
        {
            if (ArenaType == 0)
            {
                ResidentHandler.Inst.GetFunction("L_RtsArenaManager.Clear").Action();
            }
            else if (ArenaType == 1)
            {
                ResidentHandler.Inst.GetFunction("L_RadarArenaManager.Clear").Action();
            }
            else
            {
                ResidentHandler.Inst.GetFunction("L_RtsExpeditionManager.Clear").Action();
            }
        }

        public void Dispose()
        {
            MarchManager.Instance?.UnsetArenaMarchContext();
            UnApplyCamera();    
            report = null;
            start = false;
            isReadyToEnd = false;
            MarchManager.Instance.IsInArena = false;
            ArmyManager.Instance.SetCameraRotation(45);
        }

        private Camera originCamera;
        
        public void SetCamera(Camera camera)
        {
            MainCamera = camera;
            MobileTouchCamera = MainCamera.GetComponent<MobileTouchCamera>();
            MarchManager.Instance?.SetArenaMarchContext(camera.transform);
            if (ScreenOrientManager.GetInstance().IsPortrait())
            {
                ArmyManager.Instance.SetCameraRotation(135);
            }
            else
            {
                ArmyManager.Instance.SetCameraRotation(45);
            }
        }

        public void LockCamera()
        {
            if (MobileTouchCamera!=null)
            {
                MobileTouchCamera.Locked = true;
            }
        }
            
        public void UnLockCamera()
        {
            if (MobileTouchCamera != null)
            {
                MobileTouchCamera.Locked = false;
            }
        }

        private void InitDrawLineTools()
        {
            // 画线工具
            DrawLineTool drawLineTool = DrawLineTool.GetInstance();
            if (!drawLineTool.IsInitialized())
            {
                drawLineTool.Initialize();
            }
            drawLineTool.SetHeight(GlobalValue.PathLineHeight);
            drawLineTool.SetFollowTarget(MainCamera.transform);
            drawLineTool.materialType = 0;
            drawLineTool.LINE_WIDTH = 0.08f;
        }

        public void RequestReport(string url,string reportId,bool needJumpToCurrentTime = false,long startTime = 0)
        {
            /*var cachedReport = reportManager.GetCachedReport(url);
            if (cachedReport != null)
            {
                Timers.inst.CallLater((o) =>
                {
                    OnReportReady(cachedReport);
                });
            }
            else*/
            {
                reportManager.reportId = reportId;
                reportManager.needJumpToCurrentTime = needJumpToCurrentTime;
                reportManager.Restart();
                reportManager.RequestReport(url);
            }
        }

        public void TestLocal(string fileName)
        {
            
        }

        public void TestUrl(string url)
        {
            
        }

        public void OnGetReportFailed(bool isTimeout = false)
        {
            if (ArenaType == 0)
            {
                ResidentHandler.Inst.GetFunction("L_RtsArenaManager.OnReportFailed").Action(isTimeout);
            }
            else if (ArenaType == 1)
            {
                ResidentHandler.Inst.GetFunction("L_RadarArenaManager.OnReportFailed").Action(isTimeout);
            }
            else
            {
                ResidentHandler.Inst.GetFunction("L_RtsExpeditionManager.OnReportFailed").Action(isTimeout);
            }
        }

        private bool hasApplyCamera = false;

        private Camera worldCamera;
        
        private void ApplyCamera()
        {
            if (!hasApplyCamera)
            {
                InitDrawLineTools();
                hasApplyCamera = true;
                worldCamera = WorldCameraManager.mainCamera;
                WorldCameraManager.mainCamera = MainCamera;
                if (GpuHudFacade.GpuFacade != null)
                {
                    var hudCamera = MainCamera.transform.Find("HudCamera");
                    if (hudCamera != null)
                    {
                        GpuHudFacade.GpuFacade.m_hudCamera = hudCamera.gameObject.GetComponent<Camera>();
                    }
                }
            }
        }

        private void UnApplyCamera()
        {
            if (hasApplyCamera)
            {
                hasApplyCamera = false;
                WorldCameraManager.mainCamera = worldCamera;
                if (worldCamera != null)
                {
                    ArmyManager.Instance.InitDrawLineTools();
                }
                worldCamera = null;
                if (GpuHudFacade.GpuFacade != null)
                {
                    var hudCamera = WorldCameraManager.mainCamera.transform.Find("HudCamera");
                    if (hudCamera != null)
                    {
                        GpuHudFacade.GpuFacade.m_hudCamera = hudCamera.gameObject.GetComponent<Camera>();
                    }
                }
            }
        }

        private Dictionary<int, Vector3> expeditionPositionMap = new Dictionary<int, Vector3>();
        
        public void SetExpeditionPosition(int positionId,float x,float z)
        {
            expeditionPositionMap[positionId] = new Vector3(x, 0, z);
        }

        public Vector3 GetExpeditionPosition(int positionId)
        {
            if (expeditionPositionMap.TryGetValue(positionId, out var position))
            {
                return position;
            }
            return Vector3.zero;
        }

        public bool IsExpeditionReport()
        {
            return ArenaType == 2;
        }
        
        
        
        private string LogContent(ArenaReportContent content)
        {
            var log = "[RTS竞技场]Content:\n";
            log += "[RTS竞技场]KeyFrame:\n";
            for (int i = 0; i < content.keyFrame.Count; i++)
            {
                log += LogKeyFrame(content.keyFrame[i]);
            }
            log += "[RTS竞技场]RoundFight:\n";
            for (int i = 0; i < content.roundFight.Count; i++)
            {
                log += LogRoundFight(content.roundFight[i]);
            }
            return log;
        }

        private string LogRoundFight(SCRoundFight roundFight)
        {
            var log = "\tSCRoundFight:\n";
            log += "\t\tFightFrameTime: " + roundFight.fightFrameTime;
            log += "\n";
            log += "\t\tFightInfo: \n";
            if (roundFight.fightInfo != null)
            {
                for (int i = 0; i < roundFight.fightInfo.Count; i++)
                {
                    log += "\t\t\tTroopId: " + roundFight.fightInfo[i].troop.uid;
                    log += "\n";
                    log += "\t\t\tElements: \n";
                    for (int j = 0; j < roundFight.fightInfo[i].elements.Count; j++)
                    {
                        if (roundFight.fightInfo[i].elements[j].source != null)
                        {
                            log += "\t\t\t\tSource: " + roundFight.fightInfo[i].elements[j].source.uid;
                            log += "\n";
                        }
                        log += "\t\t\t\tAmount: " + roundFight.fightInfo[i].elements[j].amount;
                        log += "\n";
                    }

                    log += "\t\t\tRage: " + roundFight.fightInfo[i].rage;
                    log += "\n";
                    log += "\t\t\tRageIndex: " + roundFight.fightInfo[i].rageHeroIndex;
                    log += "\n";
                }
            }
            log += "\n";
            return log;
        }
        
        private string LogKeyFrame(TroopMarchKeyFrame keyFrame)
        {
            var log = "\tKeyFrame:\n";
            log += "\t\tLastFrameTime: " + keyFrame.lastFrameTime;
            log += "\n";
            log += "\t\tTroopId: " + keyFrame.troopId;
            log += "\n";
            log += "\t\tModifyFlag: " + Convert.ToString (keyFrame.modifyFlag, 2);
            log += "\n";
            log += "\t\tTargetId: " + keyFrame.targetId;
            if (RtsConvertDataFactory.IsFieldModified(keyFrame.modifyFlag, 4))
            {
                log += "(✔)";
            }
            log += "\n";
            if (keyFrame.attackTarget != null)
            {
                log += "\t\tAttackTargetId: " + keyFrame.attackTarget.uid;
                if (RtsConvertDataFactory.IsFieldModified(keyFrame.modifyFlag, 8))
                {
                    log += "(✔)";
                }
                log += "\n";
            }
            log += "\t\tMarchStatus: " + keyFrame.marchStatus;
            if (RtsConvertDataFactory.IsFieldModified(keyFrame.modifyFlag, 6))
            {
                log += "(✔)";
            }
            log += "\n";
            if (keyFrame.pathList != null)
            {
                log += "\t\tPathList: ";
                if (RtsConvertDataFactory.IsFieldModified(keyFrame.modifyFlag, 9))
                {
                    log += "(✔)";
                }
                log += "\n";
                for (int i = 0; i < keyFrame.pathList.Count; i++)
                {
                    log += string.Format("\t\t\t({0},{1})",keyFrame.pathList[i].xAxis,keyFrame.pathList[i].zAxis);
                    log += "\n";
                }
            }
            log += "\t\tBesiegeFinalAngle: " + keyFrame.besiegeFinalAngle;
            if (RtsConvertDataFactory.IsFieldModified(keyFrame.modifyFlag, 7))
            {
                log += "(✔)";
            }
            log += "\n";
            return log;
        }
        
        private string LogSummary(ArenaReportSummary summary)
        {
            var content = "[RTS竞技场]report summary:\n";
            content += LogCamp(summary.leftCamp);
            content += "\n";
            content += LogCamp(summary.rightCamp);
            return content;
        }

        private string LogCamp(ArenaBattleCamp camp)
        {
            var content = "reportCamp:\n";
            content += "\tCampId: " + camp.campId;
            content += "\n";
            content += "\tPlayerInfo: " + camp.playerInfo.nickname;
            content += "\n";
            content += "\tTroops: ";
            content += "\n";
            if (camp.troops != null)
            {
                for (int i = 0; i < camp.troops.Count; i++)
                {
                    var troop = camp.troops[i];
                    content += "\t\tTroopId: " + troop.troopId;
                    content += "\n";
                    content += "\t\t\tPositionId: " + troop.initPos;
                    content += "\n";
                    content += "\t\t\tSoldierId: " + troop.soldier.key;
                    content += "\n";
                    content += "\t\t\tSoldierCount: " + troop.soldier.value;
                    content += "\n";
                }
            }
            content += "\tPower: " + camp.teamPower;
            content += "\n";
            return content;
        }
    }
}
